#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include "cJSON.h"
#include "shmem.h"
#include "msg_queue_peer.h"

union val_t
{
    int b_val;   // bool类型存储空间
    int i_val;   // 整形值存储空间
    float f_val; // 浮点值存储空间
};

struct std_node
{
    int key;             // 唯一键值
    int type;            // 数据点类型
    int dev_type;        // 数据点属于哪个设备，根据网关支持的设备自行定义
    union val_t old_val; // 变化上报后需要更新旧值
    union val_t new_val; // 从共享内存取出最新数据，放到new_val中
    int ret;             // 默认为-1，采集成功后设置为0，采集失败再置-1
};

typedef struct
{
    long type;
    int a;
    char b[128];
}msg_t;

float tem,hum,mass;
int led,buzzer,fire,infrared,fan,motor;

void *fun(void *arg)
{
    int std_num = 9;
    size_t shm_size = sizeof(int) + sizeof(struct std_node) * std_num;
    struct shm_param para;
    if (shm_init(&para, "shm", shm_size) < 0)
    {
        printf("shm init err\n");
        return NULL;
    }
    // 获取共享内存的起始地址
    void *shm_base_addr = shm_getaddr(&para);
    if (shm_base_addr == (void *)-1 || shm_base_addr == NULL)
    {
        printf("shm get addr err\n");
        return NULL;
    }
    // 将共享内存的起始部分强制转换为我们的头部,读取设备数量
    int *header = (int *)shm_base_addr;
 
    //  数据数组紧随头部之后
    struct std_node *std_array = (struct std_node *)((char *)shm_base_addr + sizeof(int));
    for (int i = 0; i < header[0]; i++)
    {
        switch (i)
        {
        case 0:
        {
            std_array[i].new_val.i_val = infrared;
            std_array[i].ret = 0;
            break;
        }
        case 1:
        {
            std_array[i].new_val.i_val = buzzer;
            std_array[i].ret = 0;
            break;
        }
        case 2:
        {
            std_array[i].new_val.i_val = led;
            std_array[i].ret = 0;
            break;
        }
        case 3:
        {
            std_array[i].new_val.f_val = tem;
            std_array[i].ret = 0;
            break;
        }
        case 4:
        {
            std_array[i].new_val.f_val = hum;
            std_array[i].ret = 0;
            break;
        }
        case 5:
        {
            std_array[i].new_val.i_val = fan;
            std_array[i].ret = 0;
            break;
        }
        case 6:
        {
            std_array[i].new_val.i_val = motor;
            std_array[i].ret = 0;
            break;
        }
        case 7:
        {
            std_array[i].new_val.i_val = fire;
            std_array[i].ret = 0;
            break;
        }
        case 8:
        {
            std_array[i].new_val.f_val = mass;
            std_array[i].ret = 0;
            break;
        }
        default:
            break;
        }
    }
    
}

void *control(void *arg)
{
    int socket = *(int *)arg;
    char msg[128];  
    while(1)
    {
        msg_queue_recv("msg", (void *)&msg, sizeof(msg), 0, 0);
        printf("type:2\n");
        cJSON *root = cJSON_Parse(msg);
        if(root == NULL)
        {
            printf("cJSON_Parse err\n");
            return NULL;
        }
        cJSON *type = cJSON_GetObjectItem(root, "type");
        if(type == NULL)
        {
            printf("cJSON_GetObjectItem err\n");
            return NULL;
        }
        int type_val = type->valueint;
        printf("type_val:%d\n", type_val);
        cJSON *data = cJSON_GetObjectItem(root, "data");
        cJSON *key = cJSON_GetObjectItem(data, "key");
        cJSON *val = cJSON_GetObjectItem(data, "val");
        printf("%s:%d\n", key->string, key->valueint);
        printf("%s:%s\n", val->string, val->valuestring);
        if(key->valueint == 102 && strcmp(val->valuestring, "true") == 0)
        {
            send(socket, "BUZ_ON", strlen("BUZ_ON"), 0);
        }
        else if(key->valueint == 102 && strcmp(val->valuestring, "false") == 0)
        {
            send(socket, "BUZ_OFF", strlen("BUZ_OFF"), 0);
        }
        else if(key->valueint == 103 && strcmp(val->valuestring, "true") == 0)
        {
            send(socket, "LED_ON", strlen("LED_ON"), 0);
        }
        else if(key->valueint == 103 && strcmp(val->valuestring, "false") == 0)
        {
            send(socket, "LED_OFF", strlen("LED_OFF"), 0);
        }
        else if(key->valueint == 106 && strcmp(val->valuestring, "true") == 0)
        {
            send(socket, "FAN_ON", strlen("FAN_ON"), 0);
        }
        else if(key->valueint == 106 && strcmp(val->valuestring, "false") == 0)
        {
            send(socket, "FAN_OFF", strlen("FAN_OFF"), 0);
        }
        else if(key->valueint == 107 && strcmp(val->valuestring, "true") == 0)
        {
            send(socket, "MOT_ON", strlen("MOT_ON"), 0);
        }
        else if(key->valueint == 107 && strcmp(val->valuestring, "false") == 0)
        {
            send(socket, "MOT_OFF", strlen("MOT_OFF"), 0);
        }
    }
}

int main(int argc, char const *argv[])
{
    if (argc != 2)
    {
        printf("please putin %s <port>\n", argv[0]);
        return -1;
    }
    // 创建套接字
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (socket < 0)
    {
        perror("socket err\n");
        return -1;
    }
    printf("sockfd:%d\n", sockfd);
    // 指定网络信息
    int opt = 1;
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    struct sockaddr_in saddr, caddr;
    int len = sizeof(caddr);
    saddr.sin_family = AF_INET;
    saddr.sin_port = htons(atoi(argv[1]));
    //saddr.sin_addr.s_addr = inet_addr(argv[1]);
    saddr.sin_addr.s_addr = INADDR_ANY;
    // 绑定套接字
    int a = bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr));
    if (a != 0)
    {
        perror("bind err");
        return -1;
    }
    else
    {
        printf("bing ok\n");
    }
    // 监听
    if (listen(sockfd, 6) < 0)
    {
        perror("listen err");
        return -1;
    }
    else
    {
        printf("listen ok\n");
    }
    while (1)
    {
        // 接受客户端连接请求
        int fd = accept(sockfd, (struct sockaddr*)&caddr, &len);
        if (fd < 0)
        {
            perror("accept err");
            return -1;
        }
        else
        {
            printf("accept ok\n");
        }
        printf("IP:%s port:%d\n",inet_ntoa(caddr.sin_addr), ntohs(caddr.sin_port));
        char buf[128] = {0};
        pthread_t tid,tid1;
        pthread_create(&tid1, NULL, control, &fd);
        pthread_detach(tid1);
        while (1)
        {
            // 接收数据
            int ret = recv(fd, buf, sizeof(buf), 0);
            if (ret < 0)
            {
                perror("recv err");
                return -1;
            }
            printf("%s\n",buf);
            sscanf(buf,"%f/%f/%f/%d/%d/%d/%d/%d/%d/",&tem,&hum,&mass,&fire,&infrared,&fan,&motor,&buzzer,&led);
            pthread_create(&tid, NULL, fun, &fd);
            pthread_detach(tid);
            memset(buf, 0, sizeof(buf));
        }
        // 关闭套接字
        close(fd);
    }
    close(sockfd);
    return 0;
}